package com.iot.hmi.protocol;

import com.github.xingshuangs.iot.common.buff.ByteReadBuff;
import com.github.xingshuangs.iot.common.buff.EByteBuffFormat;
import com.github.xingshuangs.iot.protocol.modbus.service.ModbusTcp;
import com.github.xingshuangs.iot.utils.ByteUtil;
import com.iot.hmi.entity.IotDevice;
import com.iot.hmi.entity.IotDeviceItem;

public class ModbusTCPServiceImpl extends AbstractProtocol {
    private ModbusTcp master = null;

    public ModbusTCPServiceImpl(IotDevice device) {
        super(device);
    }

    @Override
    public void connect() {
        final ModbusTcp modbus = new ModbusTcp(
                1, deviceInfo().getProtocolHost(), deviceInfo().getProtocolPort()
        );
        modbus.setConnectTimeout(3000);
        modbus.setEnableReconnect(true);
        if (!modbus.checkConnected()) {
            modbus.connect();
        }
        this.master = modbus;
    }

    @Override
    public String read(IotDeviceItem item) {
        if (!isConnected()) {
            return null;
        }
        final byte[] bytes = master.readHoldRegister(
                Integer.parseInt(item.getItemAddress()),
                getQuantityByType(item.getItemType())
        );
        return bytes == null ? null : convertType(bytes, item.getItemType(), item.getItemStyle());
    }

    @Override
    public void disConnect() {
        if (this.master == null) {
            return;
        }
        if (this.master.checkConnected()) {
            this.master.close();
        }
    }

    @Override
    public boolean isConnected() {
        if (this.master == null) {
            return false;
        }
        return master.checkConnected();
    }

    public static int getQuantityByType(String type) {
        switch (type) {
            case "uint32":
            case "int32":
            case "float16":
            case "float32":
                return 2;
            case "float64":
                return 4;
            default:
                return 1;
        }
    }

    public static String convertType(byte[] bytes, String type, String txCode) {
        int var1;
        switch (type) {
            case "boolean":
                final boolean bool = getBuff(bytes, txCode).getBoolean(0, 0);
                return Boolean.toString(bool);
            case "byte":
                final StringBuilder builder = new StringBuilder();
                for (byte b : bytes) {
                    builder.append(String.format("%02X", b));
                }
                return builder.toString();
            case "uint16":
                var1 = getBuff(bytes, txCode).getUInt16();
                return Integer.toString(var1);
            case "int16":
                var1 = getBuff(bytes, txCode).getInt16();
                return Integer.toString(var1);
            case "uint32":
                final long var2 = getBuff(bytes, txCode).getUInt32();
                return Long.toString(var2);
            case "int32":
                var1 = getBuff(bytes, txCode).getInt32();
                return Integer.toString(var1);
            case "float16":
            case "float32":
                final float var3 = getBuff(bytes, txCode).getFloat32();
                return Float.toString(var3);
            case "float64":
                final double var4 = getBuff(bytes, txCode).getFloat64();
                return Double.toString(var4);
            case "string":
                return ByteUtil.toStr(bytes);
            default:
                return null;
        }
    }

    public static ByteReadBuff getBuff(byte[] bytes, String txCode) {
        switch (txCode) {
            case "BADC":
                return ByteReadBuff.newInstance(bytes, EByteBuffFormat.BA_DC);
            case "CDAB":
                return ByteReadBuff.newInstance(bytes, EByteBuffFormat.CD_AB);
            case "DCBA":
                return ByteReadBuff.newInstance(bytes, EByteBuffFormat.DC_BA);
            default:
                return ByteReadBuff.newInstance(bytes, EByteBuffFormat.AB_CD);
        }
    }
}
